﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Security.Cryptography;
using System.Text.RegularExpressions;
using System.IO;
using System.Net;
using System.Net.Sockets;

namespace MediaServer.Utilities
{
    /// <summary>
    /// Wrapper for a single file object.
    /// </summary>
    public class SharedFile : IDIDLSerializable
    { 
        /// <summary>
        /// Resource protocolInfo values by file extension.
        /// </summary>
        static Dictionary<string, string> protocols = new Dictionary<string, string>
        {
	        {".png", "http-get:*:image/jpeg:*"},
	        {".jpeg", "http-get:*:image/jpeg:*"},
	        {".jpg", "http-get:*:image/png:*"},
            {".mp3", "http-get:*:audio/mpeg:*"},
            {".avi", "http-get:*:video/mpeg:*"}
        };

        /// <summary>
        /// UPnP class values by file extension.
        /// </summary>
        static Dictionary<string, string> types = new Dictionary<string, string>
        {
	        {".png", "object.item.imageItem.photo"},
	        {".jpeg", "object.item.imageItem.photo"},
	        {".jpg", "object.item.imageItem.photo"},
	        {".mp3", "object.item.audioItem.musicTrack"},
            {".avi", "object.item.videoItem"}
        };

        protected string name;
        protected string ext;
        protected string url;
        protected string path;
        protected string parent;
        protected long length;
        protected string id;

        protected SharedFile() { }
        public SharedFile(string path, string parent)
        {
            this.path = path;
            this.parent = parent;
            this.id = this.GenerateID();

            var fi = new FileInfo(path);
            this.name = fi.Name;
            this.length = fi.Length;
            this.ext = fi.Extension;

            var address = "127.0.0.1";
            foreach (IPAddress ip in Dns.GetHostEntry(Dns.GetHostName()).AddressList)
            {
                if (ip.AddressFamily == AddressFamily.InterNetwork)
                {
                   address = ip.ToString();
                   break;
                }
            }

            this.url = String.Format("http://{0}:12080/{1}/{2}", address, this.id, fi.Name);
            Console.WriteLine(this.url);
        }

        private string GetUPnPClass()
        {
            if (types.ContainsKey(this.ext))
            {
                return types[this.ext];
            }
            else
            {
                Console.WriteLine("Unrecognized class " + this.path);
                return "";  // unrecognized file
            }
        }

        private string GetProtocol()
        {
            if (protocols.ContainsKey(this.ext))
            {
                return protocols[this.ext];
            }
            else
            {
                Console.WriteLine("Unrecognized file " + this.path);
                return "";  // unrecognized file
            }
        }

        /// <summary>
        /// Generates MD5 hash of this file.
        /// </summary>
        private string GenerateID()
        {
            using (var md5 = MD5.Create())
            {
                md5.ComputeHash(Encoding.UTF8.GetBytes(this.path));
                return BitConverter.ToString(md5.Hash);
            }
        }

        /// <summary>
        /// Attempts to recursively find an object by given ID.
        /// </summary>
        /// <param name="id">ID of the object.</param>
        /// <returns>Returns 'this' if ID matched this file, null otherwise.</returns>
        public IDIDLSerializable Find(string id)
        {
            return (this.id.Equals(id)) ? this : null;
        }

        /// <summary>
        /// Prepare raw results for Browse query.
        /// </summary>
        /// <returns>
        /// List containing this file.
        /// </returns>
        public List<IDIDLSerializable> Browse()
        {
            List<IDIDLSerializable> results = new List<IDIDLSerializable>();
            results.Add(this);
            return results;
        }

        public XmlElement SingleXML(XmlDocument doc)
        {
            XmlElement container = doc.CreateElement("item");
            container.SetAttribute("id", this.id);
            container.SetAttribute("parentID", this.parent);
            container.SetAttribute("restricted", "1");
            container.AppendChild(doc.CreateElement("dc:title", "dc")).InnerText = this.name;
            container.AppendChild(doc.CreateElement("upnp:class", "upnp")).InnerText = this.GetUPnPClass();
            var resource = doc.CreateElement("res");
            resource.InnerText = this.url;
            resource.SetAttribute("protocolInfo", this.GetProtocol());
            resource.SetAttribute("size", this.length.ToString());
            container.AppendChild(resource);
            return container;
        }

        public override string ToString()
        {
            return this.path;
        }


        public bool Matches(string SearchCriteria)
        {
            Match match = Regex.Match(SearchCriteria, "^dc:title = \"(.*)\"$");
            return match.Groups.Count > 1 && this.name.Contains(match.Groups[1].Value);
        }
    }

    class VirtualFile : SharedFile
    {
        public VirtualFile(string name, string parent, string id, string url)
        {
            this.name = name;
            this.parent = parent;
            this.id = id;
            this.url = url;
        }

        public string GetURL()
        {
            return this.url;
        }

        public override string ToString()
        {
            return this.name;
        }
    }
}
